<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>面向对象高级</title>
</head>

<body>
    <script>
        /**
         * 1.对象创建模式
         *      1.方式1：Object构造函数模式
         *          先创建空Obeject对象，然后动态添加属性、方法
                    使用场景：起初不确定对象内部数据
                    问题：语句太多
                2. 对象字面量模式
                    使用{}创建对象，同时指定属性、方法
                    使用场景：起初时对象内部数据是确定的
                    问题：如果创建多个对象，有重复代码
                3.工厂模式
                    通过工厂函数动态创建对象并返回
                    使用场景：需要创建多个对象
                    问题：对象没有一个具体的类型，都是Object类型
                4. 自定义构造函数模式
                    自定义构造函数，通过new创建对象
                    使用场景：需要创建多个类型确定的对象
                    问题：每个对象都有相同的数据，浪费内存
        */
        /**
        * 案例1，Object构造函数模式
        * 适用场景:起始时不确定对象内部数据
        * 缺点:语句太多
       */
        // var p = new Object()
        // p.name = 'zhangsan'
        // p.age = 18
        // p.setName = function(name){
        // 	this.name = name
        // }
        /**
        * 案例2，对象字面量模式
        * 适用场景:起始时对象内部数据是确定的
        * 缺点:如果创建多个对象,有重复代码
       */
        // var p = {
        //     name: 'zhangsan',
        //     age: 18,
        //     setName: function () {
        //         this.name = name
        //     }
        // }

        //要是创建多个对象 就像下面这样产生了重复代码
        // var p2 = {
        //     name: 'lisi',
        //     age: 30,
        //     setName: function () {
        //         this.name = name
        //     }
        // }
        /**
         * 案例3，工厂模式 通过工厂函数动态创建对象并返回【工厂函数:返回一个对象的函数】
         * 适用场景:需要创建多个对象
         * 缺点:创建出来的对象没有联系 不能识别创建出来的对象属于哪个类型,对象没有一个具体的类型,都是Object类型
        */
        // function createPerson(name, age) {
        //     var obj = {
        //         name: name,
        //         age: age,
        //         setName: function (name) {
        //             this.name = name
        //         }
        //     }
        //     return obj;
        // }
        //创建两个人
        // var p1 = createPerson('Tom', 12)
        // var p2 = createPerson('Bob', 18)
        /**
        * 案例4，自定义构造函数模式
        * 适用场景:需要创建多个类型确定的对象
        * 缺点:每个对象都有相同的数据,浪费内存 //看着好像没什么问题  但是在它的每个实例都有一个setName方法 占用了内存
       */
        // function Person(name, age) {
        //     this.name = name;
        //     this.age = age;
        //     this.setName = function (name) {
        //         this.name = name;
        //     }
        // }
        // var p1 = new Person('Tom', 12);
        // p1.setName('Jack');
        // console.log(p1.name, p1.age);// Jack 12

        // function Student(name, price) {
        //     this.name = name
        //     this.price = price
        // }
        // var s = new Student('Bob', 13000)
        // console.log(s instanceof Student)//true
        /**
       * 案例5，构造函数+原型的组合模式
       * 自定义构造函数，属性在函数中初始化，方法添加到原型上
       * 使用场景：需要创建多个类型确定的对象
      */
        // function Person(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }

        // Person.prototype.setName = function (name) {
        //     this.name = name;
        // }
        /**
         * 继承模式
                原型链继承

                    定义父类的构造函数，给父类的原型添加方法
                    定义子类的构造函数
                    创建父类的对象赋值给子类的原型
                    将子类的原型的构造属性设置为子类型
                    给子类型原型添加方法
                    创建子类型的对象：可以调用父类型的方法
                    关键：子类型的原型为父类型的实例
        */
        // //父类型
        // function Father(name) {
        //     this.name = name + '12'
        //     this.supProp = 'father property'
        // }
        // Father.prototype.show = function () {
        //     //给父类的原型添加方法
        //     console.log(this.supProp)
        // }

        // //子类型
        // function Son(name) {
        //     // this.name=name+'123'
        //     this.subProp = 'son property'
        // }
        // Son.prototype = new Father('ceshi') // 这是关键，子类型的原型为父类型的实例
        // Son.prototype.constructor = Son // 让子类的原型的constructor指向子类型,不实现此举，则Son的构造函数为Father
        // Son.prototype.show2 = function () {
        //     console.log(this.subProp)
        // }

        // var son = new Son('ceshi')
        // son.show()  // father property
        // son.show2()
        // console.log(son.constructor, son instanceof Father)
        /**
         * 借用构造函数继承
        */
        // function Person(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // function Student(name, age, price) {
        //     Person.call(this, name, age)  //相当于 this.Person(name.age)

        //     // this.name = name;
        //     // this.age = age;

        //     this, price = price;
        // }

        // var s = new Student('Tom', 20, 14000)
        // console.log(s.name, s.age, s.price);
        /**
         * 组合继承
        */
        // function Person(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }
        // Person.prototype.setName = function (name) {
        //     this.name = name;
        // }
        // function Student(name, age, price) {
        //     Person.call(this, name, age)  //相当于 this.Person(name.age)

        //     // this.name = name;
        //     // this.age = age;

        //     this.price = price;
        // }
        // Student.prototype = new Person()  // 为了能看到父类的方法
        // Student.prototype.constructor = Student //修正constructor属性
        // Student.prototype.setPrice = function (price) {
        //     this.price = price
        // }

        // var s = new Student('Tom', 24, 15000)
        // s.setName('Bob')
        // s.setPrice(16000)
        // console.log(s.name, s.age, s.price) // Bob 24 16000


        function Person(name, age, sex, job) {
            this.name = name;
            this.age = age;
            this.sex = sex;
            this.job = job;
        }

        Person.prototype.eat = function () {
            console.log(`我是${this.job}${this.name},我正在吃东西`)
        }

        function Boss(name, age, sex, job, thing) {
            Person.call(this, name, age, sex, job);
            this.thing = thing
        }
        Boss.prototype = new Person();
        Boss.prototype.constructor = Boss;
        Boss.prototype.bossThing = function (thing) {
            this.thing = thing
            console.log(`我是${this.job}${this.name}，我要${this.thing}`)
        }
        function manager(name, age, sex, job, thing) {
            Person.call(this, name, age, sex, job);
            this.thing = thing
        }
        manager.prototype = new Person();
        manager.prototype.constructor = manager;
        manager.prototype.managerThing = function (thing) {
            this.thing = thing
            console.log(`我是${this.job}${this.name},我要${this.thing}`)
        }

        function worker(name, age, sex, job, thing) {
            Person.call(this, name, age, sex, job);
            this.thing = thing
        }
        worker.prototype = new Person();
        worker.prototype.constructor = worker;
        worker.prototype.workerThing = function (thing) {
            this.thing = thing
            console.log(`我是${this.job}${this.name},我要${this.thing}`)
        }




        var xiaolong = new Boss('WXL', 21, '男', '老板', '打员工');
        var donglin = new manager('QDL', 22, '男', '管理层', '');
        var zhixiong = new worker('李智雄', 22, '男', '员工', '');

        xiaolong.bossThing('打老婆')
        xiaolong.eat()
        donglin.managerThing('骂人')
        donglin.eat()
        zhixiong.workerThing('辞职回家种田')
        zhixiong.eat()



    </script>
</body>

</html>